home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / vmSwapDir.c < prev    next >
C/C++ Source or Header  |  1990-09-12  |  12KB  |  421 lines

  1. /* 
  2.  * vmSwapDir.c --
  3.  *
  4.  *    This file synchronizes opening and reopening of the VM swap
  5.  *    directory.  The swap directory is used for error recovery.
  6.  *    It provides a FS handle on which the VM module can wait.
  7.  *    During error conditions the swap directory is reopened,
  8.  *    and this needs to be synchronized so more than one process
  9.  *    doesn't attempt to do it.  This monitor calls FS routines,
  10.  *    and as a rule the main VM monitor lock should not be held
  11.  *    during calls into FS, so these routines also should not be
  12.  *    called from within VM routines protected by vmMonitorLock.
  13.  *
  14.  *    The routines that create and remove swap files are also in
  15.  *    this module as they are one of the primary uses of the monitored
  16.  *    set of procedures.
  17.  *
  18.  * Copyright 1989 Regents of the University of California
  19.  * Permission to use, copy, modify, and distribute this
  20.  * software and its documentation for any purpose and without
  21.  * fee is hereby granted, provided that the above copyright
  22.  * notice appear in all copies.  The University of California
  23.  * makes no representations about the suitability of this
  24.  * software for any purpose.  It is provided "as is" without
  25.  * express or implied warranty.
  26.  */
  27.  
  28. #ifndef lint
  29. static char rcsid[] = "$Header: /sprite/src/kernel/vm/RCS/vmSwapDir.c,v 1.6 90/09/12 13:36:44 shirriff Exp $ SPRITE (Berkeley)";
  30. #endif /* not lint */
  31.  
  32. #include <sprite.h>
  33. #include <fs.h>
  34. #include <vm.h>
  35. #include <vmInt.h>
  36. #include <sync.h>
  37. #include <vmSwapDir.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <stdlib.h>
  41.  
  42. static Sync_Lock vmSwapDirLock = Sync_LockInitStatic("vmSwapDirLock");
  43. #define LOCKPTR &vmSwapDirLock
  44.  
  45. /*
  46.  * This is the variable for which access needs to be synchronized.
  47.  */
  48. Fs_Stream    *vmSwapStreamPtr = (Fs_Stream *)NIL;
  49.  
  50. /*
  51.  * This is a reference count to the swap stream.  It can't be reopened
  52.  * while someone is using it for recovery.
  53.  */
  54. static int swapStreamUsers = 0;
  55.  
  56. /*
  57.  * This indicates if a reopen is in progress.  Only one reopen at a time
  58.  * is allowed.
  59.  */
  60. static Boolean reopenInProgress = FALSE;
  61.  
  62. Boolean vmSwapFileDebug = FALSE;
  63.  
  64.  
  65. /*
  66.  *----------------------------------------------------------------------
  67.  *
  68.  * Vm_OpenSwapDirectory --
  69.  *
  70.  *    Open the swap directory for this machine.  This is used to
  71.  *    optimize naming operations on the swap file, and, more importantly,
  72.  *    this open directory gives VM a handle on which to wait for recovery.
  73.  *    This routine will retry periodically until it successfully opens
  74.  *    the swap directory.  This handles multiple invocations, and it
  75.  *    takes care of closing the existing stream to the directory
  76.  *    if needed.
  77.  *
  78.  * Results:
  79.  *    None.
  80.  *
  81.  * Side effects:
  82.  *    Swap directory stream pointer is set.
  83.  *
  84.  *----------------------------------------------------------------------
  85.  */
  86. /* ARGSUSED */
  87. ENTRY void
  88. Vm_OpenSwapDirectory(data, callInfoPtr)
  89.     ClientData        data;    
  90.     Proc_CallInfo    *callInfoPtr;
  91. {
  92.     char        number[34];
  93.     char        fileName[FS_MAX_PATH_NAME_LENGTH];
  94.     ReturnStatus    status;
  95.  
  96.     LOCK_MONITOR;
  97.  
  98.     /*
  99.      * Synchronize with processes using the swap stream pointer for recovery.
  100.      * We just try again later, instead of blocking this Proc_ServerProc
  101.      * on a condition variable.
  102.      */
  103.     if (swapStreamUsers > 0) {
  104.     callInfoPtr->interval = 20 * timer_IntOneSecond;
  105.     UNLOCK_MONITOR;
  106.     return;
  107.     }
  108.  
  109.     if (vmSwapStreamPtr != (Fs_Stream *) NIL) {
  110.     (void) Fs_Close(vmSwapStreamPtr);
  111.     vmSwapStreamPtr = (Fs_Stream *) NIL;
  112.     printf("Reopening swap directory.\n");
  113.     }
  114.  
  115.     (void)strcpy(fileName, VM_SWAP_DIR_NAME);
  116.     (void)sprintf(number, "%u", (unsigned) Sys_GetHostId());
  117.     (void)strcat(fileName, number);
  118.     status = Fs_Open(fileName, FS_FOLLOW, FS_DIRECTORY, 0, &vmSwapStreamPtr);
  119.     if (status != SUCCESS) {
  120.     /*
  121.      * It didn't work, retry in 20 seconds.
  122.      */
  123.     callInfoPtr->interval = 20 * timer_IntOneSecond;
  124.     vmSwapStreamPtr = (Fs_Stream *)NIL;
  125.     } else {
  126.     reopenInProgress = FALSE;
  127.     }
  128.     UNLOCK_MONITOR;
  129. }
  130.  
  131. /*
  132.  *----------------------------------------------------------------------
  133.  *
  134.  * VmOpenSwapFile --
  135.  *
  136.  *    Open a swap file for this segment.  Store the name of the swap
  137.  *    file with the segment.
  138.  *
  139.  * Results:
  140.  *    SUCCESS unless swap file could not be opened.
  141.  *
  142.  * Side effects:
  143.  *    Swap file pointer is set in the segment's data struct.
  144.  *
  145.  *----------------------------------------------------------------------
  146.  */
  147. ReturnStatus
  148. VmOpenSwapFile(segPtr)
  149.     register    Vm_Segment    *segPtr;
  150. {
  151.     int                status;
  152.     Proc_ControlBlock        *procPtr;
  153.     int                origID = NIL;
  154.     char            fileName[FS_MAX_PATH_NAME_LENGTH];
  155.     char            *swapFileNamePtr;
  156.     Fs_Stream            *swapDirPtr;
  157.     Fs_Stream            *origCwdPtr = (Fs_Stream *)NIL;
  158.  
  159.     if (segPtr->swapFileName == (char *) NIL) {
  160.     /*
  161.      * There is no swap file yet so open one.  This may entail assembling 
  162.      * the file name first.  The file name is the segment number.
  163.      */
  164.     VmMakeSwapName(segPtr->segNum, fileName);
  165.     segPtr->swapFileName = (char *) malloc(strlen(fileName) + 1);
  166.     (void) strcpy(segPtr->swapFileName, fileName);
  167.     }
  168. #ifdef SWAP_FILE_DEBUG
  169.     printf("Opening swap file %s.\n", segPtr->swapFileName);
  170. #endif /* SWAP_FILE_DEBUG */
  171.     procPtr = Proc_GetEffectiveProc();
  172.     if (procPtr->effectiveUserID != PROC_SUPER_USER_ID) {
  173.     origID = procPtr->effectiveUserID;
  174.     procPtr->effectiveUserID = PROC_SUPER_USER_ID;
  175.     }
  176.     /*
  177.      * We want the swap file open to happen relative to the swap directory
  178.      * for this machine if possible.  This is so that if the swap directory
  179.      * is a symbolic link and the swap open fails we know that it failed
  180.      * because the swap server is down, not the server of the symbolic link.
  181.      */
  182.     swapDirPtr = VmGetSwapStreamPtr();
  183.     if (swapDirPtr != (Fs_Stream *)NIL) {
  184.     origCwdPtr = procPtr->fsPtr->cwdPtr;
  185.     procPtr->fsPtr->cwdPtr = swapDirPtr;
  186.     (void)sprintf(fileName, "%u", (unsigned) segPtr->segNum);
  187.     swapFileNamePtr = fileName;
  188.     } else {
  189.     swapFileNamePtr = segPtr->swapFileName;
  190.     }
  191.     status = Fs_Open(swapFileNamePtr, 
  192.              FS_READ | FS_WRITE | FS_CREATE | FS_TRUNC | FS_SWAP,
  193.              FS_FILE, 0660, &segPtr->swapFilePtr);
  194.     if (origID != NIL) {
  195.     procPtr->effectiveUserID = origID;
  196.     }
  197.     if (swapDirPtr != (Fs_Stream *)NIL) {
  198.     procPtr->fsPtr->cwdPtr = origCwdPtr;
  199.     VmDoneWithSwapStreamPtr();
  200.     }
  201.     if (status != SUCCESS) {
  202.     printf("%s VmOpenSwapFile: Could not open swap file %s, reason 0x%x\n", 
  203.         "Warning:", segPtr->swapFileName, status);
  204.     return(status);
  205.     }
  206.  
  207.     segPtr->flags |= VM_SWAP_FILE_OPENED;
  208.  
  209.     return(SUCCESS);
  210. }
  211.  
  212.  
  213. /*
  214.  *----------------------------------------------------------------------
  215.  *
  216.  * VmMakeSwapName --
  217.  *
  218.  *    Given a buffer to hold the name of the swap file, return the
  219.  *    name corresponding to the given segment.  FileName is assumed to
  220.  *    hold a string long enough for the maximum swap file name.
  221.  *
  222.  * Results:
  223.  *    The pathname is returned in fileName.
  224.  *
  225.  * Side effects:
  226.  *    None.
  227.  *
  228.  *----------------------------------------------------------------------
  229.  */
  230. void
  231. VmMakeSwapName(segNum, fileName)
  232.     int  segNum;        /* segment for which to create name */ 
  233.     char *fileName;        /* pointer to area to hold name */
  234. {
  235.     char number[34];
  236.  
  237.     (void)strcpy(fileName, VM_SWAP_DIR_NAME);
  238.     (void)sprintf(number, "%u", (unsigned) Sys_GetHostId());
  239.     (void)strcat(fileName, number);
  240.     (void)strcat(fileName, "/");
  241.     (void)sprintf(number, "%u", (unsigned) (segNum));
  242.     (void)strcat(fileName, number);
  243. }
  244.  
  245.  
  246. /*
  247.  *----------------------------------------------------------------------
  248.  *
  249.  * VmSwapFileRemove --
  250.  *
  251.  *    Remove the swap file for the given segment.
  252.  *
  253.  *    NOTE: This does not have to be synchronized because it is assumed
  254.  *          that it is called after the memory for the process has already
  255.  *          been freed thus the swap file can't be messed with.
  256.  *
  257.  * Results:
  258.  *    None.
  259.  *
  260.  * Side effects:
  261.  *    The swap file is removed.
  262.  *----------------------------------------------------------------------
  263.  */
  264. void
  265. VmSwapFileRemove(swapStreamPtr, swapFileName)
  266.     Fs_Stream    *swapStreamPtr;
  267.     char    *swapFileName;
  268. {
  269.     Proc_ControlBlock    *procPtr;
  270.     int            origID = NIL;
  271.     ReturnStatus    status;
  272.  
  273.     (void)Fs_Close(swapStreamPtr);
  274.     procPtr = Proc_GetEffectiveProc();
  275.     if (procPtr->effectiveUserID != PROC_SUPER_USER_ID) {
  276.     origID = procPtr->effectiveUserID;
  277.     procPtr->effectiveUserID = PROC_SUPER_USER_ID;
  278.     }
  279.     if (swapFileName != (char *) NIL) {
  280.     if (vmSwapFileDebug) {
  281.         status = SUCCESS;
  282.         printf("VmSwapFileRemove: not removing swap file %s.\n",
  283.                swapFileName);
  284.     } else {
  285.         status = Fs_Remove(swapFileName);
  286.     }
  287.     if (status != SUCCESS) {
  288.         printf("Warning: VmSwapFileRemove: Fs_Remove(%s) returned %x.\n",
  289.               swapFileName, status);
  290.         if (status == FS_FILE_NOT_FOUND) {
  291.         /*
  292.          * This can happen if the swap file itself is removed,
  293.          * or if the directory gets changed.  Reopen the directory
  294.          * to make sure.
  295.          */
  296.         VmReopenSwapDirectory();
  297.         }
  298.     }
  299.     free(swapFileName);
  300.     }
  301.     if (origID != NIL) {
  302.     procPtr->effectiveUserID = origID;
  303.     }
  304. }
  305.  
  306.  
  307. /*
  308.  * ----------------------------------------------------------------------------
  309.  *
  310.  * VmReopenSwapDirectory --
  311.  *
  312.  *    Reopen the swap stream that is used for recovery.
  313.  *    
  314.  * Results:
  315.  *    None.  
  316.  *
  317.  * Side effects:
  318.  *    Enqueues a callback to do the real work of the reopen.
  319.  *    Sets reopenInProgress so only one re-open of the swap directory occurs.
  320.  *
  321.  * ----------------------------------------------------------------------------
  322.  */
  323. void
  324. VmReopenSwapDirectory()
  325. {
  326.     LOCK_MONITOR;
  327.     if (!reopenInProgress) {
  328.     reopenInProgress = TRUE;
  329.     Proc_CallFunc(Vm_OpenSwapDirectory, (ClientData) NIL, 0);
  330.     }
  331.     UNLOCK_MONITOR;
  332. }
  333.  
  334. /*
  335.  * ----------------------------------------------------------------------------
  336.  *
  337.  * VmGetSwapStreamPtr --
  338.  *
  339.  *    Return the swap stream pointer.  This has to be followed by
  340.  *    a call to VmDoneWithSwapStreamPtr if NIL is not returned.
  341.  *    
  342.  *
  343.  * Results:
  344.  *    NIL or a valid swap stream pointer.  
  345.  *
  346.  * Side effects:
  347.  *    Increments the count of users of the swap stream.
  348.  *
  349.  * ----------------------------------------------------------------------------
  350.  */
  351. Fs_Stream *
  352. VmGetSwapStreamPtr()
  353. {
  354.     Fs_Stream *streamPtr;
  355.     LOCK_MONITOR;
  356.     streamPtr = vmSwapStreamPtr;
  357.     if (streamPtr != (Fs_Stream *)NIL) {
  358.     swapStreamUsers++;
  359.     }
  360.     UNLOCK_MONITOR;
  361.     return(streamPtr);
  362. }
  363.  
  364.  
  365. /*
  366.  * ----------------------------------------------------------------------------
  367.  *
  368.  * VmDoneWithSwapStreamPtr --
  369.  *
  370.  *    This is called after the swap stream has been used, either to
  371.  *    open a swap file or to wait for recovery.
  372.  *    
  373.  *
  374.  * Results:
  375.  *    None.  
  376.  *
  377.  * Side effects:
  378.  *    Decrements the number of users of the swap stream.
  379.  *
  380.  * ----------------------------------------------------------------------------
  381.  */
  382. void
  383. VmDoneWithSwapStreamPtr()
  384. {
  385.     LOCK_MONITOR;
  386.     swapStreamUsers--;
  387.     UNLOCK_MONITOR;
  388. }
  389.  
  390. /*
  391.  * ----------------------------------------------------------------------------
  392.  *
  393.  * VmSwapStreamOk --
  394.  *
  395.  *    Returns TRUE if it is ok to use the swap stream for recovery.
  396.  *    This is called after a PageWrite has failed.  Because this just
  397.  *    returns a snapshot of the vmSwapStreamPtr the following scenarios
  398.  *    are possible.  If the vmSwapStreamPtr gets closed after we return
  399.  *    "ok", then the sharers of the Vm segment won't have been killed,
  400.  *    but the page will still be on the dirty list, so they'll die
  401.  *    the next time the page gets written out.
  402.  *
  403.  * Results:
  404.  *    TRUE or FALSE.  
  405.  *
  406.  * Side effects:
  407.  *    None.
  408.  *
  409.  * ----------------------------------------------------------------------------
  410.  */
  411. Boolean
  412. VmSwapStreamOk()
  413. {
  414.     Boolean ok;
  415.     LOCK_MONITOR;
  416.     ok = (vmSwapStreamPtr != (Fs_Stream *)NIL);
  417.     UNLOCK_MONITOR;
  418.     return(ok);
  419. }
  420.  
  421.